package zjy.android.radapter.converter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.IllegalFormatFlagsException;

import okhttp3.ResponseBody;
import retrofit2.Converter;
import zjy.android.radapter.annotation.ReturnCode;
import zjy.android.radapter.annotation.ReturnData;
import zjy.android.radapter.exception.HttpReturnException;

public final class ReturnConverter implements Converter<ResponseBody, Object> {

    private final Gson gson;
    private final Type dataType;
    private final Class<?> returnSource;

    public ReturnConverter(Gson gson, Type dataType, Class<?> returnSource) {
        this.gson = gson;
        this.dataType = dataType;
        this.returnSource = returnSource;
    }

    @Nullable
    @Override
    public Object convert(@NonNull ResponseBody value) throws IOException {
        Field dataField = null;
        Field codeField = null;
        int[] codes = null;
        ReturnCode returnCode;
        for (Field field : returnSource.getDeclaredFields()) {
            if (field.getAnnotation(ReturnData.class) != null) {
                dataField = field;
            } else if ((returnCode = field.getAnnotation(ReturnCode.class)) != null) {
                codes = returnCode.value();
                codeField = field;
            }
        }
        if (dataField == null) {
            throw new IllegalFormatFlagsException("ReturnData == null");
        } else if (codeField == null) {
            throw new IllegalFormatFlagsException("ReturnCode == null");
        }
        JsonReader reader = gson.newJsonReader(value.charStream());
        Object source = gson.getAdapter(TypeToken.get(returnSource)).read(reader);
        try {
            Object code = codeField.get(source);
            if (code == null) throw new NullPointerException("code == null");
            for (int c : codes) {
                if (code.equals(c)) {
                    dataField.setAccessible(true);
                    String dataJson = gson.toJson(dataField.get(source));
                    Object data = gson.fromJson(dataJson, dataType);
                    dataField.set(source, data);
                    return data;
                }
            }
            throw new HttpReturnException(source);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new IllegalFormatFlagsException("illegal format");
    }
}
